| Conditions | 39 | 
| Paths | 0 | 
| Total Lines | 407 | 
| Lines | 0 | 
| Ratio | 0 % | 
| Changes | 1 | ||
| Bugs | 0 | Features | 1 | 
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like exports.publish often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | "use strict"; | ||
| 489 | exports.publish = function(taffyData, opts, tutorials) { | ||
| 490 | data = taffyData; | ||
| 491 | |||
| 492 |   conf['default'] = conf['default'] || {}; | ||
| 493 | |||
| 494 | var templatePath = opts.template; | ||
| 495 | view = new template.Template(templatePath + '/tmpl'); | ||
| 496 | |||
| 497 | // claim some special filenames in advance, so the All-Powerful Overseer of Filename Uniqueness | ||
| 498 | // doesn't try to hand them out later | ||
| 499 | // var indexUrl = helper.getUniqueFilename( 'index' ); | ||
| 500 | // don't call registerLink() on this one! 'index' is also a valid longname | ||
| 501 | |||
| 502 | // var globalUrl = helper.getUniqueFilename( 'global' ); | ||
| 503 |   helper.registerLink('global', globalUrl); | ||
| 504 | |||
| 505 | // set up templating | ||
| 506 | // set up templating | ||
| 507 | view.layout = conf['default'].layoutFile ? | ||
| 508 | path.getResourcePath(path.dirname(conf['default'].layoutFile), | ||
| 509 | path.basename(conf['default'].layoutFile) ) : 'layout.tmpl'; | ||
| 510 | |||
| 511 | // set up tutorials for helper | ||
| 512 | helper.setTutorials(tutorials); | ||
| 513 | |||
| 514 | data = helper.prune(data); | ||
| 515 | |||
| 516 | var sortOption = navOptions.sort === undefined ? opts.sort : navOptions.sort; | ||
| 517 | sortOption = sortOption === undefined ? true : sortOption; | ||
| 518 | sortOption = sortOption === true ? 'longname, version, since' : sortOption; | ||
| 519 |   if (sortOption) { | ||
| 520 | data.sort(sortOption); | ||
| 521 | } | ||
| 522 | helper.addEventListeners(data); | ||
| 523 | |||
| 524 |   var sourceFiles = {}; | ||
| 525 | var sourceFilePaths = []; | ||
| 526 |   data().each(function(doclet) { | ||
| 527 | doclet.attribs = ''; | ||
| 528 | |||
| 529 |     if (doclet.examples) { | ||
| 530 |       doclet.examples = doclet.examples.map(function(example) { | ||
| 531 | var caption, lang; | ||
| 532 | |||
| 533 | // allow using a markdown parser on the examples captions (surrounded by useless HTML p tags) | ||
| 534 |         if (example.match(/^\s*(<p>)?<caption>([\s\S]+?)<\/caption>(\s*)([\s\S]+?)(<\/p>)?$/i)) { | ||
| 535 | caption = RegExp.$2; | ||
| 536 | example = RegExp.$4 + (RegExp.$1 ? '' : RegExp.$5); | ||
| 537 | } | ||
| 538 | |||
| 539 |         var lang = /{@lang (.*?)}/.exec(example); | ||
| 540 | |||
| 541 |         if (lang && lang[1]) { | ||
| 542 | example = example.replace(lang[0], ""); | ||
| 543 | lang = lang[1]; | ||
| 544 | |||
| 545 |         } else { | ||
| 546 | lang = null; | ||
| 547 | } | ||
| 548 | |||
| 549 |         return { | ||
| 550 | caption: caption || '', | ||
| 551 | code: example, | ||
| 552 | lang: lang || "javascript" | ||
| 553 | }; | ||
| 554 | }); | ||
| 555 | } | ||
| 556 |     if (doclet.see) { | ||
| 557 |       doclet.see.forEach(function(seeItem, i) { | ||
| 558 | doclet.see[i] = hashToLink(doclet, seeItem); | ||
| 559 | }); | ||
| 560 | } | ||
| 561 | |||
| 562 | // build a list of source files | ||
| 563 | var sourcePath; | ||
| 564 |     if (doclet.meta) { | ||
| 565 | sourcePath = getPathFromDoclet(doclet); | ||
| 566 |       sourceFiles[sourcePath] = { | ||
| 567 | resolved: sourcePath, | ||
| 568 | shortened: null | ||
| 569 | }; | ||
| 570 | |||
| 571 | //Check to see if the array of source file paths already contains | ||
| 572 | // the source path, if not then add it | ||
| 573 |       if (sourceFilePaths.indexOf(sourcePath) === -1) { | ||
| 574 | sourceFilePaths.push(sourcePath) | ||
| 575 | } | ||
| 576 | } | ||
| 577 | }); | ||
| 578 | |||
| 579 | // update outdir if necessary, then create outdir | ||
| 580 |   var packageInfo = (find({ | ||
| 581 | kind: 'package' | ||
| 582 | }) || [])[0]; | ||
| 583 |   if (navOptions.disablePackagePath !== true && packageInfo && packageInfo.name) { | ||
| 584 |     if (packageInfo.version) { | ||
| 585 | outdir = path.join(outdir, packageInfo.name, packageInfo.version); | ||
| 586 |     } else { | ||
| 587 | outdir = path.join(outdir, packageInfo.name); | ||
| 588 | } | ||
| 589 | } | ||
| 590 | fs.mkPath(outdir); | ||
| 591 | |||
| 592 | // copy the template's static files to outdir | ||
| 593 | var fromDir = path.join( templatePath, 'static' ); | ||
| 594 | var staticFiles = fs.ls( fromDir, 3 ); | ||
| 595 | |||
| 596 | 	staticFiles.forEach( function ( fileName ) { | ||
| 597 | var toDir = fs.toDir( fileName.replace( fromDir, outdir ) ); | ||
| 598 | fs.mkPath( toDir ); | ||
| 599 | fs.copyFileSync( fileName, toDir ); | ||
| 600 | } ); | ||
| 601 | |||
| 602 | // copy user-specified static files to outdir | ||
| 603 | var staticFilePaths; | ||
| 604 | var staticFileFilter; | ||
| 605 | var staticFileScanner; | ||
| 606 |     if (conf.default.staticFiles) { | ||
| 607 | // The canonical property name is `include`. We accept `paths` for backwards compatibility | ||
| 608 | // with a bug in JSDoc 3.2.x. | ||
| 609 | staticFilePaths = conf.default.staticFiles.include || | ||
| 610 | conf.default.staticFiles.paths || | ||
| 611 | []; | ||
| 612 |         staticFileFilter = new (require('jsdoc/src/filter')).Filter(conf.default.staticFiles); | ||
| 613 |         staticFileScanner = new (require('jsdoc/src/scanner')).Scanner(); | ||
| 614 | |||
| 615 |         staticFilePaths.forEach(function(filePath) { | ||
| 616 | var extraStaticFiles = staticFileScanner.scan([filePath], 10, staticFileFilter); | ||
| 617 | |||
| 618 |             extraStaticFiles.forEach(function(fileName) { | ||
| 619 | var sourcePath = fs.toDir(filePath); | ||
| 620 | var toDir = fs.toDir( fileName.replace(sourcePath, outdir) ); | ||
| 621 | fs.mkPath(toDir); | ||
| 622 | fs.copyFileSync(fileName, toDir); | ||
| 623 | }); | ||
| 624 | }); | ||
| 625 | } | ||
| 626 | |||
| 627 |   if (sourceFilePaths.length) { | ||
| 628 | var payload = navOptions.sourceRootPath; | ||
| 629 |     if (!payload) { | ||
| 630 | payload = path.commonPrefix(sourceFilePaths); | ||
| 631 | } | ||
| 632 | sourceFiles = shortenPaths(sourceFiles, payload); | ||
| 633 | } | ||
| 634 |   data().each(function(doclet) { | ||
| 635 | var url = helper.createLink(doclet); | ||
| 636 | helper.registerLink(doclet.longname, url); | ||
| 637 | |||
| 638 | // add a shortened version of the full path | ||
| 639 | var docletPath; | ||
| 640 |     if (doclet.meta) { | ||
| 641 | docletPath = getPathFromDoclet(doclet); | ||
| 642 |       if (!_.isEmpty(sourceFiles[docletPath])) { | ||
| 643 | docletPath = sourceFiles[docletPath].shortened; | ||
| 644 |         if (docletPath) { | ||
| 645 | doclet.meta.shortpath = docletPath; | ||
| 646 | } | ||
| 647 | } | ||
| 648 | } | ||
| 649 | }); | ||
| 650 | |||
| 651 |   data().each(function(doclet) { | ||
| 652 | var url = helper.longnameToUrl[doclet.longname]; | ||
| 653 | |||
| 654 |     if (url.indexOf('#') > -1) { | ||
| 655 | doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop(); | ||
| 656 |     } else { | ||
| 657 | doclet.id = doclet.name; | ||
| 658 | } | ||
| 659 | |||
| 660 |     if (needsSignature(doclet)) { | ||
| 661 | addSignatureParams(doclet); | ||
| 662 | addSignatureReturns(doclet); | ||
| 663 | addAttribs(doclet); | ||
| 664 | } | ||
| 665 | }); | ||
| 666 | |||
| 667 | // do this after the urls have all been generated | ||
| 668 |   data().each(function(doclet) { | ||
| 669 | doclet.ancestors = getAncestorLinks(doclet); | ||
| 670 | |||
| 671 |     if (doclet.kind === 'member') { | ||
| 672 | addSignatureTypes(doclet); | ||
| 673 | addAttribs(doclet); | ||
| 674 | } | ||
| 675 | |||
| 676 |     if (doclet.kind === 'constant') { | ||
| 677 | addSignatureTypes(doclet); | ||
| 678 | addAttribs(doclet); | ||
| 679 | doclet.kind = 'member'; | ||
| 680 | } | ||
| 681 | }); | ||
| 682 | |||
| 683 | var members = helper.getMembers(data); | ||
| 684 | members.tutorials = tutorials.children; | ||
| 685 | |||
| 686 | // add template helpers | ||
| 687 | view.find = find; | ||
| 688 | view.linkto = linkto; | ||
| 689 | view.resolveAuthorLinks = resolveAuthorLinks; | ||
| 690 | view.tutoriallink = tutoriallink; | ||
| 691 | view.htmlsafe = htmlsafe; | ||
| 692 | view.moment = moment; | ||
| 693 | |||
| 694 | // once for all | ||
| 695 | buildNav(members); | ||
| 696 | view.nav = navigationMaster; | ||
| 697 | view.navOptions = navOptions; | ||
| 698 |   attachModuleSymbols(find({ | ||
| 699 | kind: ['class', 'function'], | ||
| 700 |       longname: { | ||
| 701 | left: 'module:' | ||
| 702 | } | ||
| 703 | }), | ||
| 704 | members.modules); | ||
| 705 | |||
| 706 | // only output pretty-printed source files if requested; do this before generating any other | ||
| 707 | // pages, so the other pages can link to the source files | ||
| 708 |   if (navOptions.outputSourceFiles) { | ||
| 709 | generateSourceFiles(sourceFiles); | ||
| 710 | } | ||
| 711 | |||
| 712 |   if (members.globals.length) { | ||
| 713 |     generate('global', 'Global', [{ | ||
| 714 | kind: 'globalobj' | ||
| 715 | }], globalUrl); | ||
| 716 | } | ||
| 717 | |||
| 718 | // some browsers can't make the dropdown work | ||
| 719 |   if (view.nav.module && view.nav.module.members.length) { | ||
| 720 |     generate('module', view.nav.module.title, [{ | ||
| 721 | kind: 'sectionIndex', | ||
| 722 | contents: view.nav.module | ||
| 723 | }], navigationMaster.module.link); | ||
| 724 | } | ||
| 725 | |||
| 726 |   if (view.nav.class && view.nav.class.members.length) { | ||
| 727 |     generate('class', view.nav.class.title, [{ | ||
| 728 | kind: 'sectionIndex', | ||
| 729 | contents: view.nav.class | ||
| 730 | }], navigationMaster.class.link); | ||
| 731 | } | ||
| 732 | |||
| 733 |   if (view.nav.namespace && view.nav.namespace.members.length) { | ||
| 734 |     generate('namespace', view.nav.namespace.title, [{ | ||
| 735 | kind: 'sectionIndex', | ||
| 736 | contents: view.nav.namespace | ||
| 737 | }], navigationMaster.namespace.link); | ||
| 738 | } | ||
| 739 | |||
| 740 |   if (view.nav.mixin && view.nav.mixin.members.length) { | ||
| 741 |     generate('mixin', view.nav.mixin.title, [{ | ||
| 742 | kind: 'sectionIndex', | ||
| 743 | contents: view.nav.mixin | ||
| 744 | }], navigationMaster.mixin.link); | ||
| 745 | } | ||
| 746 | |||
| 747 |   if (view.nav.interface && view.nav.interface.members.length) { | ||
| 748 |     generate('interface', view.nav.interface.title, [{ | ||
| 749 | kind: 'sectionIndex', | ||
| 750 | contents: view.nav.interface | ||
| 751 | }], navigationMaster.interface.link); | ||
| 752 | } | ||
| 753 | |||
| 754 |   if (view.nav.external && view.nav.external.members.length) { | ||
| 755 |     generate('external', view.nav.external.title, [{ | ||
| 756 | kind: 'sectionIndex', | ||
| 757 | contents: view.nav.external | ||
| 758 | }], navigationMaster.external.link); | ||
| 759 | } | ||
| 760 | |||
| 761 |   if (view.nav.tutorial && view.nav.tutorial.members.length) { | ||
| 762 |     generate('tutorial', view.nav.tutorial.title, [{ | ||
| 763 | kind: 'sectionIndex', | ||
| 764 | contents: view.nav.tutorial | ||
| 765 | }], navigationMaster.tutorial.link); | ||
| 766 | } | ||
| 767 | |||
| 768 | // index page displays information from package.json and lists files | ||
| 769 |   var files = find({ | ||
| 770 | kind: 'file' | ||
| 771 | }), | ||
| 772 |     packages = find({ | ||
| 773 | kind: 'package' | ||
| 774 | }); | ||
| 775 | |||
| 776 |   generate('index', 'Index', | ||
| 777 | packages.concat( | ||
| 778 |       [{ | ||
| 779 | kind: 'mainpage', | ||
| 780 | readme: opts.readme, | ||
| 781 | longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page' | ||
| 782 | }] | ||
| 783 | ).concat(files), | ||
| 784 | indexUrl); | ||
| 785 | |||
| 786 | // set up the lists that we'll use to generate pages | ||
| 787 | var classes = taffy(members.classes); | ||
| 788 | var modules = taffy(members.modules); | ||
| 789 | var namespaces = taffy(members.namespaces); | ||
| 790 | var mixins = taffy(members.mixins); | ||
| 791 | var interfaces = taffy(members.interfaces); | ||
| 792 | var externals = taffy(members.externals); | ||
| 793 | |||
| 794 |   for (var longname in helper.longnameToUrl) { | ||
| 795 |     if (hasOwnProp.call(helper.longnameToUrl, longname)) { | ||
| 796 |       var myClasses = helper.find(classes, { | ||
| 797 | longname: longname | ||
| 798 | }); | ||
| 799 |       if (myClasses.length) { | ||
| 800 |         generate('class', 'Class: ' + myClasses[0].name, myClasses, helper.longnameToUrl[longname]); | ||
| 801 | } | ||
| 802 | |||
| 803 |       var myModules = helper.find(modules, { | ||
| 804 | longname: longname | ||
| 805 | }); | ||
| 806 |       if (myModules.length) { | ||
| 807 |         generate('module', 'Module: ' + myModules[0].name, myModules, helper.longnameToUrl[longname]); | ||
| 808 | } | ||
| 809 | |||
| 810 |       var myNamespaces = helper.find(namespaces, { | ||
| 811 | longname: longname | ||
| 812 | }); | ||
| 813 |       if (myNamespaces.length) { | ||
| 814 |         generate('namespace', 'Namespace: ' + myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname]); | ||
| 815 | } | ||
| 816 | |||
| 817 |       var myMixins = helper.find(mixins, { | ||
| 818 | longname: longname | ||
| 819 | }); | ||
| 820 |       if (myMixins.length) { | ||
| 821 |         generate('mixin', 'Mixin: ' + myMixins[0].name, myMixins, helper.longnameToUrl[longname]); | ||
| 822 | } | ||
| 823 | |||
| 824 |       var myInterfaces = helper.find(interfaces, { | ||
| 825 | longname: longname | ||
| 826 | }); | ||
| 827 |       if (myInterfaces.length) { | ||
| 828 |         generate('interface', 'Interface: ' + myInterfaces[0].name, myInterfaces, helper.longnameToUrl[longname]); | ||
| 829 | } | ||
| 830 | |||
| 831 |       var myExternals = helper.find(externals, { | ||
| 832 | longname: longname | ||
| 833 | }); | ||
| 834 |       if (myExternals.length) { | ||
| 835 |         generate('external', 'External: ' + myExternals[0].name, myExternals, helper.longnameToUrl[longname]); | ||
| 836 | } | ||
| 837 | } | ||
| 838 | } | ||
| 839 | |||
| 840 | // TODO: move the tutorial functions to templateHelper.js | ||
| 841 |   function generateTutorial(title, tutorial, filename) { | ||
| 842 |     var tutorialData = { | ||
| 843 | title: title, | ||
| 844 | header: tutorial.title, | ||
| 845 | content: tutorial.parse(), | ||
| 846 | children: tutorial.children, | ||
| 847 | docs: null | ||
| 848 | }; | ||
| 849 | |||
| 850 | var tutorialPath = path.join(outdir, filename), | ||
| 851 |       html = view.render('tutorial.tmpl', tutorialData); | ||
| 852 | |||
| 853 |     // yes, you can use {@link} in tutorials too! | ||
| 854 |     html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a> | ||
| 855 | |||
| 856 |     if (searchEnabled) { | ||
| 857 |       searchableDocuments[filename] = { | ||
| 858 | "id": filename, | ||
| 859 | "title": title, | ||
| 860 | "body": searchData(html) | ||
| 861 | }; | ||
| 862 | } | ||
| 863 | |||
| 864 | fs.writeFileSync(tutorialPath, html, 'utf8'); | ||
| 865 | } | ||
| 866 | |||
| 867 | // tutorials can have only one parent so there is no risk for loops | ||
| 868 |   function saveChildren(node) { | ||
| 869 |     node.children.forEach(function(child) { | ||
| 870 |       generateTutorial('Tutorial: ' + child.title, child, helper.tutorialToUrl(child.name)); | ||
| 871 | saveChildren(child); | ||
| 872 | }); | ||
| 873 | } | ||
| 874 | |||
| 875 |   function generateQuickTextSearch(templatePath, searchableDocuments, navOptions) { | ||
| 876 |       var data = { | ||
| 877 | searchableDocuments: JSON.stringify(searchableDocuments), | ||
| 878 | navOptions: navOptions | ||
| 879 | }; | ||
| 880 | |||
| 881 | var tmplString = fs.readFileSync(templatePath + "/quicksearch.tmpl").toString(), | ||
| 882 | tmpl = _.template(tmplString); | ||
| 883 | |||
| 884 | var html = tmpl(data), | ||
| 885 | outpath = path.join(outdir, "quicksearch.html"); | ||
| 886 | |||
| 887 | fs.writeFileSync(outpath, html, "utf8"); | ||
| 888 | } | ||
| 889 | |||
| 890 | saveChildren(tutorials); | ||
| 891 | |||
| 892 |   if (searchEnabled) { | ||
| 893 | generateQuickTextSearch(templatePath + '/tmpl', searchableDocuments, navOptions); | ||
| 894 | } | ||
| 895 | }; | ||
| 896 |